home *** CD-ROM | disk | FTP | other *** search
- // Copyright 1994 by Jon Dart. All Rights Reserved.
-
- #include "movegen.h"
- #include "bearing.h"
- #include "emove.h"
- #include "rmove.h"
- #include "scoring.h"
- #include "moveord.h"
- #include "util.h"
- #include <iostream.h>
- #ifdef RANGE_CHECK
- #include <assert.h>
- #endif
-
- Move_Generator::Move_Generator(const Board & ABoard,
- const unsigned ply, const Move & last_move):
- board(ABoard), my_ply(ply), my_last_move(last_move)
- {
- }
-
- Move_Generator::~Move_Generator()
- {
- }
-
- inline void Move_Generator::
- SetMove(const Square source, const Square dest,
- const Piece::PieceType promotion, Move * moves, unsigned &NumMoves)
- {
- #ifdef RANGE_CHECK
- assert(source.OnBoard());
- assert(dest.OnBoard());
- assert(NumMoves <= Move_Generator::MaxMoves);
- #endif
- moves[NumMoves] = Move(source, dest, promotion);
- ++NumMoves;
- }
-
- int Move_Generator::
- Generate_Moves(Move * moves, const Boolean captures_only,
- const Boolean repeatable)
- {
- unsigned NumMoves;
- if (board.CheckStatus() == Board::InCheck)
- {
- NumMoves = Check_Evasions(moves);
- }
- else
- {
- NumMoves = 0;
-
- // castling moves
- if (!captures_only)
- {
- const ColorType side = board.Side();
- Board::CastleType CS = board.CastleStatus(side);
- if ((CS == Board::CanCastleEitherSide) ||
- (CS == Board::CanCastleKSide))
- {
- const Square kp = board.KingPos(side);
- if (board[kp + 1].IsEmpty() &&
- board[kp + 2].IsEmpty() &&
- board.num_attacks(kp,OppositeColor(side)) == 0 &&
- board.num_attacks(kp + 1,OppositeColor(side)) == 0 &&
- board.num_attacks(kp + 2,OppositeColor(side)) == 0)
- // can castle
- SetMove(kp, kp + 2,
- Piece::Invalid,
- moves, NumMoves);
- }
- if ((CS == Board::CanCastleEitherSide) ||
- (CS == Board::CanCastleQSide))
- {
- const Square kp = board.KingPos(side);
- if (board[kp - 1].IsEmpty() &&
- board[kp - 2].IsEmpty() &&
- board[kp - 3].IsEmpty() &&
- board.num_attacks(kp,OppositeColor(side)) == 0 &&
- board.num_attacks(kp - 1,OppositeColor(side)) == 0 &&
- board.num_attacks(kp - 2,OppositeColor(side)) == 0)
- // can castle
- SetMove(kp, kp - 2,
- Piece::Invalid,
- moves, NumMoves);
- }
- }
- // other moves
- static Square squares[Bearing::MaxBearSq];
-
- for (int i = 0; i < 16; i++)
- {
- Square loc = board.PiecePos(board.Side(), i);
- if (!loc.IsInvalid())
- {
- int n = Bearing::BearSq(board, loc, squares);
- const Piece piecemoved = board[loc];
- for (int j = 0; j < n; j++)
- {
- const Square dest(squares[j]);
- int promotion =
- piecemoved.Type() == Piece::Pawn &&
- dest.Rank(board.Side()) == 8;
- if (promotion)
- {
- SetMove(loc, dest, Piece::Queen, moves, NumMoves);
- SetMove(loc, dest, Piece::Rook, moves, NumMoves);
- SetMove(loc, dest, Piece::Bishop, moves, NumMoves);
- SetMove(loc, dest, Piece::Knight, moves, NumMoves);
- }
- else if (captures_only)
- {
- if (!board[dest].IsEmpty() ||
- ((piecemoved.Type() == Piece::Pawn) &&
- (dest.File() != loc.File())))
- SetMove(loc, dest, Piece::Invalid, moves, NumMoves);
- }
- else
- SetMove(loc, dest, Piece::Invalid, moves, NumMoves);
- }
- }
- }
- }
-
- if (repeatable)
- {
- int *scores = new int[NumMoves];
- for (int i = 0; i < NumMoves; i++)
- {
- scores[i] = moves[i].StartSquare() & (moves[i].DestSquare() << 7);
- switch (moves[i].PromoteTo())
- {
- case Piece::Queen:
- scores[i] &= 0xB000;
- break;
- case Piece::Rook:
- scores[i] &= 0x8000;
- break;
- case Piece::Bishop:
- scores[i] &= 0x4000;
- break;
- default:
- break;
- }
- }
- Move_Ordering::sort_moves(moves, scores, NumMoves);
- delete[] scores;
- }
- return NumMoves;
- }
-
- static Boolean is_pinned(const Board & board, const Square source,
- const Square dest)
- {
- Boolean pin = False;
- if (board.num_attacks(source, board.OppositeSide()) > 0)
- {
- // It is possible that the piece we plan to move is pinned.
- Piece PinnedByPiece;
- Square PinnedBySquare;
- int dir;
- if (Bearing::Pinned(board, source, PinnedByPiece,
- PinnedBySquare, dir))
- {
- // This code checks for moves in the direction of the pin,
- // which are ok:
- int dir1 = Util::Abs((int) source - (int) dest);
- int dir2 = Util::Abs(dir);
- if (dir2 == 1 && source.Rank() != dest.Rank())
- pin = True;
- else if (dir2 == RankIncr && source.File() != dest.File())
- pin = True;
- else if (dir1 % dir2)
- pin = True;
- }
- }
- return pin;
- }
-
- unsigned Move_Generator::Check_Evasions(Move * moves)
- {
- int num_moves = 0;
- unsigned n;
- unsigned i;
- static Square squares[36];
- Square source;
- const Square kp = board.KingPos(board.Side());
- unsigned num_attacks = board.num_attacks(kp, board.OppositeSide());
- const int double_check = num_attacks > 1;
- if (!double_check)
- {
- // try to capture checking piece
- unsigned n = Bearing::Attack(board, kp, board.OppositeSide(), squares);
- assert(n);
- source = squares[0];
- #ifdef RANGE_CHECK
- assert(!board[source].IsEmpty() && board[source].Type() != Piece::King);
- #endif
- n = Bearing::Attack(board, source, board.Side(), squares);
- for (i = 0; i < n; i++)
- {
- if (board[squares[i]].Type() == Piece::King)
- {
- // We can capture with the king only if the piece
- // checking us is undefended.
- if (board.num_attacks(source, board.OppositeSide()) == 0)
- moves[num_moves++] = Move(squares[i], source);
- }
- else
- {
- if (!is_pinned(board, squares[i], source))
- moves[num_moves++] = Move(squares[i], source);
- }
- }
- // Bearing::Attack does not return en passant captures, so try
- // this as a special case
- if (board.EnPassantSq(board.OppositeSide()) == source)
- {
- Square dest(source + RankIncr * Direction[board.Side()]);
- Piece myPawn(Piece::Pawn,board.Side());
- if (source.File() != 8 && board[source + 1] == myPawn)
- {
- Piece tmp(board[source]);
- Piece &place = (Piece &)board[source];
- place = Piece::EmptyPiece(); // imagine me gone
- if (!is_pinned(board, source + 1, dest))
- moves[num_moves++] = Move(source + 1, dest);
- place = tmp;
- }
- if (source.File() != 1 && board[source - 1] == myPawn)
- {
- Piece tmp(board[source]);
- Piece &place = (Piece &)board[source];
- place = Piece::EmptyPiece(); // imagine me gone
- if (!is_pinned(board, source - 1, dest))
- moves[num_moves++] = Move(source - 1, dest);
- place = tmp;
- }
- }
- // try to interpose a piece
- if (board[source].Type() != Piece::Knight &&
- board[source].Type() != Piece::Pawn)
- {
- Square btwn_squares[8];
- unsigned nbsq = board.Between(source, kp, btwn_squares);
- for (i = 0; i < nbsq; i++)
- {
- n = Bearing::Attack(board, btwn_squares[i],
- board.Side(), squares);
- for (unsigned j = 0; j < n; j++)
- {
- if (board[squares[j]].Type() != Piece::King &&
- !is_pinned(board, squares[j], btwn_squares[i]))
- moves[num_moves++] = Move(squares[j], btwn_squares[i]);
- }
- }
- }
- }
- // generate evasive moves
- n = Bearing::BearSq(board, kp, squares);
- Square atck_squares[8];
- unsigned num_attackers = Bearing::Attack(board, kp,
- board.OppositeSide(), atck_squares);
- for (i = 0; i < n; i++)
- {
- if (board.num_attacks(squares[i], board.OppositeSide()) == 0)
- if (double_check || squares[i] != source)
- {
- // We need to do some extra checking, since the board
- // info on attacks reflects the state before the move,
- // and we need to be sure that the destination square
- // is not attacked after the move.
- Boolean illegal = False;
- for (int j = 0; j < num_attackers && !illegal; j++)
- {
- Piece attacker(board[atck_squares[j]]);
- if (attacker.sliding())
- {
- int dir = board.Direction(atck_squares[j], squares[i]);
- // check for movement in the direction of the
- // attacker:
- if (dir != 0 && (kp + dir == squares[i]))
- illegal = True;
- }
- }
- if (!illegal)
- moves[num_moves++] = Move(kp, squares[i]);
- }
- }
- return num_moves;
- }
-